class PreloadManager {
	constructor() {
		this.cacheMetaKey = 'preload_file_meta_v7';
		this.cacheContentKeyPrefix = 'preload_file_content_';
		this.maxSmallFileSize = 1 * 1024 * 1024; // 1MB小型文件阈值

		this.memoryCache = new Map(); // 键：标准化URL，值：base64（小型）/持久化路径（大型）
		this.fileMetaCache = {};

		this.supportLocalStorage = this._checkLocalStorageSupport();
		this._init();
	}

	// -------------------------- 基础工具方法 --------------------------
	_checkLocalStorageSupport() {
		try {
			const testKey = 'preload_test_key';
			uni.setStorageSync(testKey, 'test');
			uni.removeStorageSync(testKey);
			return true;
		} catch (e) {
			console.warn('[Preload] localStorage不可用：', e);
			return false;
		}
	}

	_normalizeUrl(url) {
		if (!url) return '';
		return url.split('?')[0].split('#')[0].trim().toLowerCase();
	}

	_generateFileKey(url) {
		const normalizedUrl = this._normalizeUrl(url);
		let hash = 0;
		for (let i = 0; i < normalizedUrl.length; i++) {
			const char = normalizedUrl.charCodeAt(i);
			hash = ((hash << 5) - hash) + char;
			hash = hash & hash;
		}
		return `file_${Math.abs(hash)}`;
	}

	_saveFileMetaToLocal() {
		if (!this.supportLocalStorage) return;
		try {
			uni.setStorageSync(this.cacheMetaKey, JSON.stringify(this.fileMetaCache));
		} catch (e) {
			console.error('[Preload] 保存元数据失败：', e);
		}
	}

	// -------------------------- 核心：修正缓存检查逻辑 --------------------------
	async isFileCached(url) {
		const normalizedUrl = this._normalizeUrl(url);
		const fileKey = this._generateFileKey(url);

		// 1. 内存缓存命中：直接返回true
		if (this.memoryCache.has(normalizedUrl)) {
			const content = this.memoryCache.get(normalizedUrl);
			return !!content;
		}

		// 2. 无元数据：返回false
		if (!this.fileMetaCache[fileKey]) {
			console.log('[Preload] 无元数据，缓存未命中');
			return false;
		}

		const meta = this.fileMetaCache[fileKey];
		// 3. 校验URL一致性
		if (this._normalizeUrl(meta.normalizedUrl) !== normalizedUrl) {
			
			delete this.fileMetaCache[fileKey];
			this._saveFileMetaToLocal();
			return false;
		}

		// 4. 小型文件：从localStorage读取base64并写入内存
		if (!meta.isLargeFile) {
			try {
				const base64Content = uni.getStorageSync(this.cacheContentKeyPrefix + fileKey);
				if (base64Content) {
					this.memoryCache.set(normalizedUrl, base64Content);
					
					return true;
				} else {
					
					delete this.fileMetaCache[fileKey];
					this._saveFileMetaToLocal();
					return false;
				}
			} catch (e) {
				console.error('[Preload] 读取小型文件缓存失败', e);
				delete this.fileMetaCache[fileKey];
				this._saveFileMetaToLocal();
				return false;
			}
		}

		// 5. 大型文件：检查持久化路径是否有效
		if (meta.isLargeFile && meta.persistentPath) {
			// 验证文件是否存在
			try {
				await new Promise((resolve, reject) => {
					uni.getFileInfo({
						filePath: meta.persistentPath,
						success: resolve,
						fail: reject
					});
				});
				// 文件存在，写入内存
				this.memoryCache.set(normalizedUrl, meta.persistentPath);
				console.log('[Preload] 大型文件持久化路径有效，写入内存');
				return true;
			} catch (e) {
				console.warn('[Preload] 大型文件路径无效，清理元数据', e);
				delete this.fileMetaCache[fileKey];
				this._saveFileMetaToLocal();
				return false;
			}
		}

		return false;
	}

	// -------------------------- 初始化与预加载 --------------------------
	_init() {
		try {
			if (this.supportLocalStorage) {
				const metaStr = uni.getStorageSync(this.cacheMetaKey);
				this.fileMetaCache = metaStr ? JSON.parse(metaStr) : {};
				this._preloadSmallFilesToMemory();
			}
		} catch (e) {
			console.error('[Preload] 初始化失败', e);
			this.fileMetaCache = {};
			this.memoryCache.clear();
		}
	}

	_preloadSmallFilesToMemory() {
		Object.values(this.fileMetaCache).forEach(meta => {
			if (!meta.isLargeFile) {
				try {
					const base64Content = uni.getStorageSync(this.cacheContentKeyPrefix + meta.fileKey);
					if (base64Content) {
						const normalizedUrl = this._normalizeUrl(meta.normalizedUrl);
						this.memoryCache.set(normalizedUrl, base64Content);
					}
				} catch (e) {
					console.warn('[Preload] 预加载失败', meta.normalizedUrl, e);
					delete this.fileMetaCache[meta.fileKey];
					this._saveFileMetaToLocal();
				}
			}
		});
	}

	// -------------------------- 下载与保存（核心修复） --------------------------
	async _downloadFile(url, fileType, onProgress) {
		return new Promise((resolve, reject) => {
			uni.downloadFile({
				url: url,
				timeout: 30000,
				success: (res) => {
					uni.hideLoading();
					if (res.statusCode === 200) {
						resolve(res.tempFilePath);
					
					} else {
						reject(new Error(`下载失败：状态码${res.statusCode}`));
					}
				},
				fail: (err) => {
					uni.hideLoading();
					reject(new Error(`下载失败：${err.errMsg}`));
				}
			});
		});
	}

	async _saveFileToLocal(url, tempPath, fileType) {
		const normalizedUrl = this._normalizeUrl(url);
		const fileKey = this._generateFileKey(url);
		const timestamp = Date.now();

		try {
			// 获取文件信息（大小）
			const fileInfo = await new Promise((resolve) => {
				uni.getFileInfo({
					filePath: tempPath,
					success: resolve,
					fail: (err) => {
						console.warn('[Preload] 获取文件大小失败', err);
						resolve({ size: this.maxSmallFileSize + 1 });
					}
				});
			});
			const isLargeFile = fileInfo.size > this.maxSmallFileSize;
			let finalContent; // 最终缓存的内容（base64或持久化路径）

				// 大型文件：保存为持久化文件（获取永久路径）
				const saveRes = await new Promise((resolve, reject) => {
					uni.saveFile({
						tempFilePath: tempPath,
						success: resolve,
						fail: reject
					});
				});
				finalContent = saveRes.savedFilePath; // 持久化路径（如wxfile://...）
			

			// 写入元数据（记录是否为大型文件及持久化路径）
			this.fileMetaCache[fileKey] = {
				url: url,
				normalizedUrl: normalizedUrl,
				fileKey: fileKey,
				fileType: fileType,
				timestamp: timestamp,
				isLargeFile: isLargeFile,
				size: fileInfo.size,
				persistentPath: isLargeFile ? finalContent : null // 大型文件记录持久化路径
			};

			// 写入内存缓存
			this.memoryCache.set(normalizedUrl, finalContent);
			this._saveFileMetaToLocal();

			return finalContent;
		} catch (e) {
			console.error('[Preload] 保存文件失败', normalizedUrl, e);
			// 失败时仍用临时路径（但可能后续失效，仅作为降级）
			this.memoryCache.set(normalizedUrl, tempPath);
			return tempPath;
		}
	}

	// -------------------------- 预加载方法 --------------------------
	async preloadFile(url, fileType, onProgress) {
		const normalizedUrl = this._normalizeUrl(url);
		if (!normalizedUrl) {
			console.warn('[Preload] 无效URL：直接返回地址', url);
			return url;
		}

		// 自动识别文件类型
		if (!fileType) {
			if (normalizedUrl.match(/\.(jpg|jpeg|png|gif|webp|bmp)$/i)) {
				fileType = 'image';
			} else if (normalizedUrl.match(/\.(mp4|mov|avi|flv|mkv|webm)$/i)) {
				fileType = 'video';
			} else {
				console.warn('[Preload] 无法识别文件类型：', normalizedUrl);
				return url;
			}
		}

		// 检查缓存
		const isCached = await this.isFileCached(url);
		if (isCached) {
			const cachedValue = this.memoryCache.get(normalizedUrl);
			
			return cachedValue;
		} else {
		
			this._downloadAndCacheFile(url, fileType, onProgress).catch(e => {
				console.error('[Preload] 后台缓存失败', normalizedUrl, e);
			});
			return url;
		}
	}

	async _downloadAndCacheFile(url, fileType, onProgress) {
		try {
			const tempPath = await this._downloadFile(url, fileType, onProgress);
			const finalSrc = await this._saveFileToLocal(url, tempPath, fileType);
			typeof onProgress === 'function' && onProgress(100);
			return finalSrc;
		} catch (e) {
			throw e;
		}
	}

	// -------------------------- 缓存清理 --------------------------
	cleanExpiredCache(maxAge = 7 * 24 * 60 * 60 * 1000) {
		if (!this.supportLocalStorage) {
			const count = this.memoryCache.size;
			this.memoryCache.clear();
			console.log('[Preload] 清理内存缓存：', count, '个');
			return count;
		}

		const now = Date.now();
		let deletedCount = 0;
		Object.keys(this.fileMetaCache).forEach(fileKey => {
			const meta = this.fileMetaCache[fileKey];
			if (now - meta.timestamp > maxAge) {
				// 清理小型文件的localStorage内容
				if (!meta.isLargeFile) {
					try {
						uni.removeStorageSync(this.cacheContentKeyPrefix + fileKey);
					} catch (e) {
						console.warn('[Preload] 删除过期小型文件：', e);
					}
				}
				// 清理大型文件的持久化路径
				if (meta.isLargeFile && meta.persistentPath) {
					try {
						uni.deleteSavedFile({
							filePath: meta.persistentPath,
							fail: (e) => console.warn('[Preload] 删除过期大型文件失败：', e)
						});
					} catch (e) {
						console.warn('[Preload] 删除过期大型文件异常：', e);
					}
				}
				// 清理内存和元数据
				this.memoryCache.delete(meta.normalizedUrl);
				delete this.fileMetaCache[fileKey];
				deletedCount++;
			}
		});

		this._saveFileMetaToLocal();
		return deletedCount;
	}

	clearAllCache() {
		this.memoryCache.clear();
		if (this.supportLocalStorage) {
			Object.keys(this.fileMetaCache).forEach(fileKey => {
				const meta = this.fileMetaCache[fileKey];
				// 清理小型文件
				if (!meta.isLargeFile) {
					try {
						uni.removeStorageSync(this.cacheContentKeyPrefix + fileKey);
					} catch (e) {
						console.warn('[Preload] 清空小型文件失败：', e);
					}
				}
				// 清理大型文件
				if (meta.isLargeFile && meta.persistentPath) {
					try {
						uni.deleteSavedFile({
							filePath: meta.persistentPath,
							fail: (e) => console.warn('[Preload] 清空大型文件失败：', e)
						});
					} catch (e) {
						console.warn('[Preload] 清空大型文件异常：', e);
					}
				}
			});
			uni.removeStorageSync(this.cacheMetaKey);
		}
		const count = Object.keys(this.fileMetaCache).length;
		this.fileMetaCache = {};
		console.log('[Preload] 清空所有缓存：', count, '个');
		return count;
	}
}

export default new PreloadManager();